import { serialize, addURLData, serializeJSON } from './utils.js'
import DEFAULTS from './defaults.js'
import { HTTP_GET, COTENT_TYPE_FORM_URLENCODED, COTENT_TYPE_JSON } from './constants.js'
class Ajax {
  constructor(url, options) {
    this.url = url
    this.options = Object.assign({}, DEFAULTS, options)
    this.init()
  }


  // 初始化
  init() {
    const xhr = new XMLHttpRequest()
    this.xhr = xhr

    // 绑定事件的响应程序
    this.bindEvent()

    // 准备发送请求
    this.xhr.open(this.options.method, this.url + this.addParam(), true)

    // 设置resopnseType
    this.setResponseType()

    // 设置超时
    this.setTimeout()

    // withCredentials的作用：跨域请求是否提供凭据信息(cookie、HTTP认证及客户端SSL证明等)
    //也可以简单的理解为，当前请求为跨域类型时是否在请求中协带cookie。
    this.setCookie()

    // 发送请求
    this.sendData()

  }
  // 绑定事件的响应程序
  bindEvent() {
    const xhr = this.xhr
    const {
      success,
      httpCodeError,
      error,
      abort,// 请求不到
      timeout } = this.options

    // load
    xhr.addEventListener('load', () => {
      if (this.ok()) {
        success(xhr.response, xhr)
      } else {
        httpCodeError(xhr.status, xhr)
      }
    })

    // error
    xhr.addEventListener('error', () => {
      error(xhr)
    })

    // abort
    xhr.addEventListener('abort', () => {
      abort(xhr)
    })

    // timeout
    xhr.addEventListener('timeout', () => {
      timeout(xhr)
    })

  }
  // 检测状态码是否正常
  ok() {
    const xhr = this.xhr
    return xhr.status >= 200 && xhr.status < 300 || xhr.status === 304
  }
  //在地址上添加数据
  addParam() {
    const { params } = this.options
    if (!params) return ''
    return addURLData(this.url, serialize(params))
  }

  // 设置resopnseType
  setResponseType() {
    this.xhr.responseType = this.options.responseType
  }

  // 设置超时
  setTimeout() {
    let { timeoutTime } = this.options
    if (timeoutTime > 0) {
      this.xhr.timeout = timeoutTime
    }
  }

  // 跨域请求是否携带cookie
  setCookie() {
    let { withCredentials } = this.options
    if (withCredentials) {
      this.xhr.withCredentials = withCredentials
    }
  }

  sendData() {
    const xhr = this.xhr
    if (!this.isSendData()) {
      return xhr.send(null)
    }
    
    let resultData = null
    const { data } = this.options
    if (this.isFormData()) {
      // 发送FormData数据
      resultData = data
    } else if (this.isFormURLEncoded()) {
      // 发送FormData格式的数据
      this.setContentType(COTENT_TYPE_FORM_URLENCODED)
      resultData = serialize(data)
    } else if (this.isJSONData()) {
      this.setContentType(COTENT_TYPE_JSON)
      // 发送 JSON格式的数据
      resultData = serializeJSON(data)
    } else {
      // 其他格式
      resultData = data
    }

    return xhr.send(resultData)
  }

  // 是否需要使用sendData发送数据
  isSendData() {
    const { data, method } = this.options
    if (!data) {
      return false
    }
    if (method.toLowerCase() === HTTP_GET.toLowerCase()) {
      return false
    }

    return true
  }

  // 判断是否 发送FormData格式的数据
  isFormData() {
    return this.options.data instanceof FormData
  }

  // 判断是否发送application/x-www-form-urlencoded格式
  isFormURLEncoded() {
    return this.options.cotentType.toLowerCase().includes(COTENT_TYPE_FORM_URLENCODED)
  }


  // 判断是否发送的是Json
  isJSONData() {
    return this.options.cotentType.toLowerCase().includes(COTENT_TYPE_JSON)
  }

  // 设置发送的数据格式
  setContentType(contentType = this.options.contentType) {
    if (!contentType) return
    this.xhr.setRequestHeader('Content-Type', contentType)
  }

  // 获取XHR对象
  getXHR() {
    return this.xhr
  }
}

export default Ajax